package cn.sumpu.app.guoguojie.biz.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import cn.sumpu.app.guoguojie.biz.MailBiz;
import cn.sumpu.app.guoguojie.biz.MemberBiz;
import cn.sumpu.app.guoguojie.dao.MailDao;
import cn.sumpu.app.guoguojie.domain.Mail;
import cn.sumpu.app.guoguojie.domain.MailLog;
import cn.sumpu.app.guoguojie.domain.Member;
import cn.sumpu.app.guoguojie.exception.AppBusinessException;
import cn.sumpu.app.guoguojie.util.Common;
import cn.sumpu.app.guoguojie.util.IdGenerator;
import cn.sumpu.app.guoguojie.util.PageModel;

public class MailBizImpl implements MailBiz {

	private String mailUsername;
	private String mailPassword;
	private String mailEmail;
	@SuppressWarnings("unused")
    private String fileServer;
	private String fileDir;
	private MailDao mailDao;
	private Properties props;
	private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(
			100);
	private ThreadPoolExecutor exec = new ThreadPoolExecutor(5, 10, 60,
			TimeUnit.SECONDS, queue);
	@Autowired
	private MemberBiz memberBiz;
	private final static Logger logger = LoggerFactory
			.getLogger(MailBizImpl.class);

	public void setMailDao(MailDao mailDao) {
		this.mailDao = mailDao;
	}

	@Override
	public void sendEmail(final String basePath, final Member member,
			final String title, final String emailContent)
			throws AppBusinessException {
		exec.submit(new Send(basePath, member, title, emailContent));

	}

	class Send implements Runnable {

		private Member member;
		private String basePath;
		private String title;
		private String emailContent;

		Send(String basePath, Member member, String title, String emailContent) {
			this.member = member;
			this.basePath = basePath;
			this.title = title;
			this.emailContent = emailContent;
		}

		@Override
		public void run() {
			Session session = Session.getInstance(props,
					new SimpleAuthenticator());
	//		session.setDebug(true);
			MimeMessage msg = new MimeMessage(session);
			try {
				msg.setFrom(new InternetAddress(mailEmail, "果果街"));
				String toEmail = member.getEmail();
				InternetAddress[] address = { new InternetAddress(toEmail) };
				msg.setRecipients(Message.RecipientType.TO, address);
				msg.setSentDate(new Date());
				if (Common.notEmptyStr(title)) {
					msg.setSubject(title);
				} else {
					msg.setSubject("欢迎入住果果街-注册邮箱验证信");
				}
				// 构造登录路径
				if (Common.notEmptyStr(emailContent)) {
					msg.setContent(emailContent, "text/html ;charset=utf-8");
				} else {
					msg.setContent(
							member.getNickname()
									+ "您好：<br /><br />"
									+ "欢迎入驻果果街！<br />请点击下面的链接完成激活：<br />"
									+ "<a href='"
									+ basePath
									+ "member/emailvalidate.htm?number="
									+ member.getIdentifier()+"&activeCode="+member.getActiveCode()
									+ "'>"
									+ basePath
									+ "member/emailvalidate.htm?number="
									+ member.getIdentifier()+"&activeCode="+member.getActiveCode()
									+ "</a>"
									+ "<br />如果以上链接无法点击，请将上面的地址复制到你的浏览器的地址输入框(如IE)的地址栏进行验证。<br /><br />"
									+ "(这是一封自动产生的email，请勿回复。)<br />"
									+ "--非常感谢您的使用！  果果街团队",
							"text/html ;charset=utf-8");
				}
				Transport.send(msg);
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();

				if (logger.isErrorEnabled()) {
					logger.error("send mail error.", e);
				}
			} catch (MessagingException e) {
				e.printStackTrace();
				if (logger.isErrorEnabled()) {
					logger.error("send mail error.", e);
				}
			}
		}
	}

	public String getMailUsername() {
		return mailUsername;
	}

	public void setMailUsername(String mailUsername) {
		this.mailUsername = mailUsername;
	}

	public String getMailPassword() {
		return mailPassword;
	}

	public void setMailPassword(String mailPassword) {
		this.mailPassword = mailPassword;
	}

	public String getMailEmail() {
		return mailEmail;
	}

	public void setMailEmail(String mailEmail) {
		this.mailEmail = mailEmail;
	}

	public Properties getProps() {
		return props;
	}

	public void setProps(Properties props) {
		this.props = props;
	}

	class SimpleAuthenticator extends Authenticator {

		@Override
		protected PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication(mailUsername, mailPassword);
		}

	}

	public void setFileServer(String fileServer) {
		this.fileServer = fileServer;
	}

	public void setFileDir(String fileDir) {
		this.fileDir = fileDir;
	}
	
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	//保存邮件任务
	@Override
	public void saveEmailTask(Mail mail) throws AppBusinessException {
		if(mail!=null){ 
			if(Common.empty(mail.getIdentifier())){
				mail.setIdentifier(IdGenerator.createIdentifier().replaceAll("-", ""));
				mail.setState("enable");
				mailDao.insertMailTask(mail);
				boolean isActive=false;
				if(mail.getIsActive().equals("01")){
					isActive=true;
				}
				String sendReadyTime=mail.getSendReadyTime();
				Integer number=mail.getNumber();
				List<Member> list=memberBiz.getAllMemberEmail(isActive);
				for (int i = 0,length=list.size(); i < length; i++) {
					String rt=getCurrentTime(sendReadyTime, (3600/number)*i);
					MailLog maillog=new MailLog();
					maillog.setIdentifier(IdGenerator.createIdentifier().replaceAll("-", ""));
					maillog.setMail(mail.getIdentifier());
					maillog.setNickname(list.get(i).getNickname());
					maillog.setEmail(list.get(i).getEmail());
					mail.setTo(list.get(i).getEmail());
					maillog.setSendReadyTime(rt);
					maillog.setState("ready");
					mailDao.insertMailTaskLog(maillog);
				}
			}else{
				String sendReadyTime=mail.getSendReadyTime();
				Mail m=getMailById(mail.getIdentifier());
				if(!sendReadyTime.equals(m.getSendReadyTime())){
					Map<String, Object> map=new HashMap<String, Object>();
					map.put("mail", mail.getIdentifier());
					List<MailLog> list=mailDao.getMailTaskLog(map);
					Integer number=mail.getNumber();
					for (int i = 0,length=list.size(); i < length; i++) {
						String rt=getCurrentTime(sendReadyTime, (int)number/3600*i);
						MailLog mailLog=list.get(i);
						mailLog.setSendReadyTime(rt);
						mailDao.updateMailTaskLog(mailLog);
					}
				}
				mailDao.updateMailTask(mail);
			}
		}
	}
	/** 
     * 计算得出时间 
     * @param time（格式为HHmmss） 
     * @param minutes 
     * @return 
     */  
    private String getCurrentTime(String time, int second){    
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        Calendar calendar = null;  
        Date dateOld = null;  
        try {
            if(time!=null){
                dateOld = df.parse(time);  
                calendar = Calendar.getInstance();  
                calendar.setTime(dateOld);  
                calendar.set(Calendar.SECOND,calendar.get(Calendar.SECOND) + second);
                return df.format(calendar.getTime());
            }
        } catch (java.text.ParseException e) {  
            logger.error("getCurrentDate failed",e);  
        }  
        return null;   
    }  
	//定时发送邮件任务
	@SuppressWarnings("unchecked")
	public  void timePostEmail(){
		try {
			Map<String, Object> map=new HashMap<String, Object>(); 
			map.put("state", "ready");
			map.put("pageSize", 10);
			List<MailLog> list= mailDao.getMailTaskLog(map);
			for (MailLog mailLog : list) {
				SimpleDateFormat timeFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
				String nowDate=timeFormat.format(new Date());
				Calendar nowCa=Calendar.getInstance();
				Calendar c2=Calendar.getInstance();
				nowCa.setTime(timeFormat.parse(nowDate));
				c2.setTime(timeFormat.parse(mailLog.getSendReadyTime()));
				int result=nowCa.compareTo(c2);
				if(result>=0){
					Mail mail=getMailById(mailLog.getMail());
					Mail m = new Mail(mail.getSmtpServer(), mail.getUsername(), "果果街",mail.getUsername(), mail.getPassword(), mailLog.getEmail(),mail.getSubject(), mail.getContent());
					m.setFile(getEmailFile(mail.getFilename()));
					HashMap<String, Object> resultMap=m.send();
					mailLog.setRemark(resultMap.get("message").toString());
					mailLog.setState(resultMap.get("state").toString());
					mailLog.setSendActualTime(nowDate);
					mailDao.updateMailTaskLog(mailLog);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void sendTestEmail(Mail mail) throws AppBusinessException {
		mail.setFrom(mail.getUsername());
		String fileStr=mail.getFilename();
		mail.setFile(getEmailFile(fileStr));
		String str = mail.getTo();
		String addr[]=str.split(",");
		for (int i = 0; i < addr.length; i++) {
			Mail m = new Mail(mail.getSmtpServer(), mail.getFrom(), "果果街",mail.getUsername(), mail.getPassword(), addr[i],mail.getSubject(), mail.getContent());
			m.setFile(mail.getFile());
			m.send(); 
		}
	}

	private Vector<File> getEmailFile(String fileStr) {
		Vector<File> file = new Vector<File>();
		String fileNameArr[]=null; 
		if(!Common.empty(fileStr)){
		    fileNameArr=fileStr.split(",");
			for (int i = 0; i < fileNameArr.length; i++) {
				File fl=new File(fileNameArr[i]);
				file.add(fl);
			}
		}
		return file;
	}

	
	@Override
	public String uploadFile(HttpServletRequest request) {
		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
		MultipartFile file = multipartRequest.getFile("file");
		if (file == null) {
			try {
				throw new Exception("上传失败：文件为空");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}else{
		    if (file.getSize() > 10000000) {
	            try {
	                throw new Exception("上传失败：文件大小不能超过10M");
	            } catch (Exception e) {
	                e.printStackTrace();
	            }
	        }
		 // 得到文件名
	        String filename = file.getOriginalFilename();
	        if (file.getSize() > 0) {
	            try {
	                String path=SaveFileFromInputStream(file.getInputStream(), fileDir,filename);
	                return path;
	            } catch (IOException e) {
	                System.out.println(e.getMessage());
	                return null;
	            }
	        } else {
	            try {
	                throw new Exception("上传失败：上传文件不能为空");
	            } catch (Exception e) {
	                e.printStackTrace();
	            }
	        }
		}
		return null;
	}

	/**
	 * 保存文件
	 * 
	 * @param stream
	 * @param path
	 * @param filename
	 * @throws IOException
	 */
	public String SaveFileFromInputStream(InputStream stream, String path,
			String filename) throws IOException {
		String date=Common.getFormatDate(new Date());
		String uuid=UUID.randomUUID().toString().replaceAll("-", "");
		path=path + "/" +date+"/"+uuid;
		File tmpPath = new File(path);
		if (!tmpPath.exists()) {
			tmpPath.mkdirs();
		}
		FileOutputStream fs = new FileOutputStream(path+"/"+filename);
		byte[] buffer = new byte[1024 * 1024];
		int bytesum = 0;
		int byteread = 0;
		while ((byteread = stream.read(buffer)) != -1) {
			bytesum += byteread;
			fs.write(buffer, 0, byteread);
			fs.flush();
		}
		fs.close();
		stream.close();
		return path+","+filename;
	}

	@Override
	public String delFile(String directoryPath,String fileName) {
	
		File file = new File(directoryPath+"/"+fileName);
		if (!file.exists()) {
			return "notExit";
		} else {
			if (file.isFile() && file.exists()) {
				file.delete();
				File dir = new File(directoryPath);
				if(dir.isDirectory()&&dir.exists()){
					dir.delete();
				}
				return "success";
			} else {
				return "error";
			}
		}
	}

	@Override
	public Mail getMailById(String id) throws AppBusinessException {
		Map<String, Object> map=new HashMap<String, Object>();
		map.put("identifier", id);
		List<Mail> list= mailDao.getMailTask(map);
		if(list!=null && list.size()>0){
			return list.get(0);
		}
		return null;
	}
	
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	@Override
	public PageModel getMailList(Integer page,Integer pageSize, String subject)
			throws AppBusinessException {
		Map<String, Object> map = new HashMap<String, Object>();
		page=page==null?1:page;
		int size=pageSize==null?10:pageSize;
		map.put("startId", (page - 1) * size);
		map.put("pageSize", size);
		if (!Common.empty(subject)) {
			map.put("subject", "%" + subject + "%");
		}
		int count = mailDao.getMailTaskCount(map);
		PageModel pm = new PageModel();
		pm.setCurrentPage(page);
		List<Mail> list=mailDao.getMailTask(map);
		pm.setList(list);
		pm.setPageSize(size);
		pm.setTotalRecord(count);
		pm.setTotalPage((count + size - 1) / size);
		return pm;
	}
	
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	@Override
	public void delEmailTask(String mailId) throws AppBusinessException {
		Map<String, Object> map1 = new HashMap<String, Object>();
		map1.put("identifier", mailId);
		mailDao.deleteMailTask(map1);
		Map<String, Object> map2 = new HashMap<String, Object>();
		map2.put("mail", mailId);
		mailDao.deleteMailTaskLog(map2);
	}

	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	@Override
	public void cancelEmailTask(String mailId) throws AppBusinessException {
		Mail mail=new Mail();
		mail.setIdentifier(mailId);
		mail.setState("cancel");
		mailDao.updateMailTask(mail);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("mail", mailId);
		List<MailLog> list=mailDao.getMailTaskLog(map);
		for (MailLog mailLog : list) {
			if(mailLog.getState().equals("ready")){
				mailLog.setState("cancel");
				mailDao.updateMailTaskLog(mailLog);
			}
		}
	}
	
	@Transactional(rollbackForClassName = { "cn.sumpu.app.guoguojie.exception.AppBusinessException" }, timeout = 10)
	@Override
	public void enableEmailTask(String mailId) throws AppBusinessException {
		Mail mail=new Mail();
		mail.setIdentifier(mailId);
		mail.setState("enable");
		mailDao.updateMailTask(mail);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("mail", mailId);
		List<MailLog> list=mailDao.getMailTaskLog(map);
		for (MailLog mailLog : list) {
			if(mailLog.getState().equals("cancel")){
				mailLog.setState("ready");
				mailDao.updateMailTaskLog(mailLog);
			}
		}
	}

	@Override
	public PageModel getMailLogList(Integer page, Integer pageSize, String mail,String nickname,String state)
			throws AppBusinessException {
		Map<String, Object> map = new HashMap<String, Object>();
		page=page==null?1:page;
		int size=pageSize==null?10:pageSize;
		map.put("startId", (page - 1) * size);
		map.put("pageSize", size);
		map.put("mail", mail);
		if (!Common.empty(nickname)) {
			map.put("nickname", "%" + nickname + "%");
		}
		if (!Common.empty(state)) {
			map.put("state", state);
		}
		int count = mailDao.getMailTaskLogCount(map); 
		PageModel pm = new PageModel();
		pm.setCurrentPage(page);
		List<MailLog> list=mailDao.getMailTaskLog(map);
		pm.setList(list);
		pm.setPageSize(size);
		pm.setTotalRecord(count);
		pm.setTotalPage((count + size - 1) / size);
		return pm;
	}
}
